LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;


ENTITY core_32 IS
PORT
	(
		clk		           : IN STD_LOGIC;
		reset              : IN STD_LOGIC;
                   
    sram_read_addr     : in std_logic_vector(17 DOWNTO 0);
    sram_read_data     : in std_logic_vector(15 DOWNTO 0);
    sram_read_valid    : IN std_logic;    
    read_request       : out std_logic;
    read_request_addr  : out std_logic_vector(17 downto 0);
    
    write_request       : out std_logic;
    write_request_addr  : out std_logic_vector(17 downto 0);
    write_request_data  : out std_logic_vector(15 downto 0);
    write_request_ack   : in std_logic
	);
END core_32;



ARCHITECTURE bhv OF core_32 IS
  
    -- inst fetch
    signal inst_ram_output : unsigned(31 downto 0);
    signal request_addr    : unsigned(6 downto 0);
    signal request_enable  : std_logic; 
  
    -- regs
    type t_reg is array(0 to 7) of unsigned(31 downto 0);
	signal regs : t_reg := (others => (others => '0'));
	
	-- load unit
	signal data_ram_output : unsigned(31 downto 0);
	signal data_ram_valid  : std_logic;
	
	-- op fetch
	signal op1 : unsigned(31 downto 0) := (others => '0');
	signal op2 : unsigned(31 downto 0) := (others => '0');
	signal target_reg_nr : unsigned(2 downto 0) := (others => '0');
	signal instruction_buffer : unsigned(31 downto 0) := (others => '0');
	
	--delay unit
	signal finished_delay : std_logic;
	
	-- execute
	signal result : unsigned(127 downto 0);
	signal target_reg_nr2 : unsigned(1 downto 0);
    type r_reg is array(0 to 3) of unsigned(31 downto 0);
	signal results : r_reg;
	signal target_reg_valid : std_logic;
	signal zeroflag : std_logic;
	
	-- writeback
	signal target_reg_nr_buffer : unsigned(2 downto 0) := (others => '0');
	signal data_ram_valid_buffer : std_logic := '0';
	signal data_ram_output_buffer : unsigned(31 downto 0) := (others => '0');
  
  component inst_fetch IS
  PORT
	( clk		           : IN STD_LOGIC;
	  reset           : in std_logic;
		sram_read_addr  : in std_logic_vector(17 DOWNTO 0);
    sram_read_data  : in std_logic_vector(15 DOWNTO 0);
    sram_read_valid : IN std_logic;
		read_request       : out std_logic;
    read_request_addr  : out std_logic_vector(17 downto 0);
	  zeroflag        : in std_logic;
	  finished_delay  : in std_logic;
		inst_ram_output : out unsigned(31 downto 0);
		request_addr    : out unsigned(6 downto 0);
		request_enable  : out std_logic
	);
  END component;

  component load_unit Is  PORT
	( clk		           : IN STD_LOGIC;
		data_ram_input  : in std_logic_vector(35 downto 0);
		data_ram_addr   : in unsigned(6 downto 0);
		data_ram_wren   : in std_logic;
		request_addr    : in unsigned(6 downto 0);
		request_enable  : in std_logic;
		data_ram_output : out unsigned(31 downto 0);
		data_ram_valid  : out std_logic
	);
  END component;


  component execute IS PORT
	( clk   : IN STD_LOGIC;
		op1   : IN unsigned(31 downto 0);
		op2   : IN unsigned(31 downto 0);
		inst  : in unsigned(31 downto 0);
		result : out unsigned(127 downto 0);
		target_reg_out : out unsigned(1 downto 0);
		target_reg_valid : out std_logic;
		zeroflag_out : out std_logic
	);
  END component;
  
  
  component delay_unit IS
  PORT
	(
		clk		               : IN STD_LOGIC;
		write_request       : out std_logic;
    write_request_addr  : out std_logic_vector(17 downto 0);
    write_request_data  : out std_logic_vector(15 downto 0);
    write_request_ack   : in std_logic;
    op1                 : IN unsigned(31 downto 0);
		op2                 : IN unsigned(31 downto 0);
		inst                : in unsigned(31 downto 0);
    finished            : out std_logic
	);
  END component;

BEGIN
	
	
	inst_fetch1 : inst_fetch PORT map
	( clk		           => clk,
	  reset           => reset,
    sram_read_addr     => sram_read_addr,
    sram_read_data     => sram_read_data,
    sram_read_valid    => sram_read_valid,
    read_request       => read_request,
    read_request_addr  => read_request_addr,
  
		zeroflag => zeroflag,
		finished_delay => finished_delay,
		inst_ram_output => inst_ram_output,
		request_addr    => request_addr,
		request_enable  => request_enable
	);
	
	load_unit1 : load_unit port map
	( clk		           => clk,
		data_ram_input  => (35 downto 0 => '0'),
		data_ram_addr   => (6 downto 0 => '0'),
		data_ram_wren   => '0',
		request_addr    => request_addr,
		request_enable  => request_enable,
		data_ram_output => data_ram_output,
		data_ram_valid  => data_ram_valid
	);
	
	
	process (clk) -- op fetch
	begin
	 if rising_edge(clk) then
	   instruction_buffer <= inst_ram_output;
	   
	   if instruction_buffer(19)='1' then -- 
	     op1 <= (31 downto 0 => '0');  
	   else
	     op1 <= regs(to_integer(instruction_buffer(18 downto 16)));
	   end if;
	   
	   if instruction_buffer(23)='1' then  -- imidiate
		  op2 <= (31 downto 16 => '0') & instruction_buffer(15 downto 0);
		 else
		  op2 <= regs(to_integer(instruction_buffer(14 downto 12)));
		 end if;
		  
		 target_reg_nr <= instruction_buffer(22 downto 20);
	 end if;  
	end process;
	
	
	delay_unit1 : delay_unit
  PORT map (
		clk		               => clk,
		write_request       => write_request,
    write_request_addr  => write_request_addr,
    write_request_data  => write_request_data,
    write_request_ack   => write_request_ack,
    op1                 => op1,
		op2                 => op2,
		inst                => instruction_buffer,
    finished            => finished_delay
	);
	
	
	execute1: execute port map
	( clk   => clk,
		op1   => op1,
		op2   => op2,
		inst  => instruction_buffer,
		result => result,
		target_reg_out => target_reg_nr2,
		target_reg_valid => target_reg_valid,
		zeroflag_out => zeroflag
	);
	results(0) <= result (31 downto 0);
	results(1) <= result (63 downto 32);
	results(2) <= result (95 downto 64);
	results(3) <= result (127 downto 96);
	
	
	process (clk)  -- writeback 
	begin
	 if rising_edge(clk) then
	  target_reg_nr_buffer <= target_reg_nr;
	  
	  data_ram_valid_buffer <= data_ram_valid;
	  data_ram_output_buffer <= data_ram_output;
	  
	  if target_reg_valid='1' then 
		  regs(to_integer(target_reg_nr_buffer))<=results(to_integer(target_reg_nr2));
		elsif data_ram_valid_buffer='1' then
		  regs(to_integer(target_reg_nr_buffer))<=data_ram_output_buffer;
		end if;
		
	 end if;
	end process;
	
	
	--reg_out <= std_logic_vector(regs(0));

END bhv;









